package top.korori.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import top.korori.common.enums.IsDel;
import top.korori.common.exception.BizException;
import top.korori.common.utils.JwtUtils;
import top.korori.common.utils.RedisCache;
import top.korori.constant.Constant;
import top.korori.constant.RedisConstant;
import top.korori.entity.SysLoginLog;
import top.korori.entity.SysUser;
import top.korori.entity.bo.LoginBo;
import top.korori.entity.model.LoginUser;
import top.korori.entity.vo.SysLoginUserVo;
import top.korori.enums.SysLoginLogStatus;
import top.korori.enums.SysUserStatus;
import top.korori.service.SysAuthService;
import top.korori.service.SysLoginLogService;
import top.korori.service.SysMenuService;
import top.korori.service.SysUserService;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * 身份认证实现类
 */
@Service
public class SysSysAuthServiceImpl implements SysAuthService {

    @Value("${token.secret}")
    public String secret;

    @Value("${token.expireTime}")
    public Long expireTime;

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private SysMenuService sysMenuService;

    @Autowired
    private SysLoginLogService sysLoginLogService;

    @Autowired
    private HttpServletRequest request;

    @Override
    public String login(LoginBo loginBo) {

        SysUser sysUser = sysUserService.getByUserNameOrEmailOrPhone(loginBo.getAccount());
        if (ObjectUtil.isNull(sysUser)) {
            String msg = "你输入的账号不存在";
            recordLog(msg, SysLoginLogStatus.FAIL.getCode(),null, loginBo.getAccount());
            BizException.cast(msg);
        }
        if (ObjectUtil.notEqual(sysUser.getPassword(),loginBo.getPassword())){
            String msg = "你输入的密码有误";
            recordLog(msg, SysLoginLogStatus.FAIL.getCode(),sysUser.getUserId(), loginBo.getAccount());
            BizException.cast(msg);
        }
        if (ObjectUtil.equal(sysUser.getStatus(), SysUserStatus.BANNED.getCode())){
            String msg = "你的账号已被"+ SysUserStatus.BANNED.getVal();
            recordLog(msg, SysLoginLogStatus.FAIL.getCode(),sysUser.getUserId(), loginBo.getAccount());
            BizException.cast(msg);
        }
        if (ObjectUtil.equal(IsDel.DELETED.getCode(),sysUser.getIsDel())){
            String msg = "你的账号已被删除";
            recordLog(msg, SysLoginLogStatus.FAIL.getCode(),sysUser.getUserId(), loginBo.getAccount());
            BizException.cast(msg);
        }


        String time = LocalDateTime.now().toString();

        JWTCreator.Builder builder = JWT.create();
        builder.withClaim(Constant.JWT_UID,sysUser.getUserId())
                .withClaim(Constant.JWT_TIME,time);
        String token = builder.withIssuedAt(new Date()) //发行时间
                .sign(Algorithm.HMAC256(secret));

        LoginUser<SysUser> loginUser = new LoginUser<>();

        loginUser.setUserId(sysUser.getUserId());
        loginUser.setTime(time);
        loginUser.setUser(sysUser);
        Set<String> perms = sysMenuService.getPermsByUserId(sysUser.getUserId());
        loginUser.setPerms(perms);

        redisCache.set(RedisConstant.SYS_USER_INFO+sysUser.getUserId(),loginUser,expireTime, TimeUnit.MINUTES);

        recordLog("登录成功", SysLoginLogStatus.OK.getCode(),sysUser.getUserId(), loginBo.getAccount());
        return token;
    }


    @Override
    public Long getUserId() {
        String token = request.getHeader(Constant.HEADER);
        String jwtToken = StrUtil.replace(token, Constant.TOKEN_PREFIX, "");
        DecodedJWT decodedJWT = JwtUtils.verify(jwtToken,secret);
        if (ObjUtil.isNull(decodedJWT)) return null;
        return decodedJWT.getClaim(Constant.JWT_UID).asLong();
    }

    @Override
    public SysLoginUserVo getLoginUser() {
        Long userId = getUserId();
        SysUser sysUser = sysUserService.getById(userId);
        return BeanUtil.copyProperties(sysUser, SysLoginUserVo.class);
    }

    @Override
    public void logout() {
        redisCache.del(RedisConstant.SYS_USER_INFO+getUserId());
    }

    public void recordLog(String msg,Integer status,Long userId,String account){
        SysLoginLog sysLoginLog = new SysLoginLog();
        sysLoginLog.setMsg(msg);
        sysLoginLog.setStatus(status);
        sysLoginLog.setUserId(userId);
        sysLoginLog.setAccount(account);
        sysLoginLogService.add(sysLoginLog);
    }

}





















